
package carmadness.model;

import java.util.List;

/**
 * A jármű számára valósítja meg a pályareprezentáció absztrakcióját (vagy így a
 * jármű független marad a konkrét pályareprezentációtól).
 * 
 * @author Metzing Arpad
 * @version 1.0
 * @created 10-Apr-2010 2:32:44 PM
 */
public class VehicleWrapper implements ISteppable
{

	/**
	 * Az az útelem, amin jelenleg tartózkodik a csomagolt jármű.
	 */
	protected RoadSegment currentRS;
	protected RoadSegmentWrapper destinationRSW;
	/**
	 * Kezdőértéke minden segmenten 1 / speed. (1 / (Segment / Tick) == Tick /
	 * Segment).
	 */
	protected int ticksRemaining;

	protected float chosenAngle;
	/**
	 * A csomagolt jármű.
	 */
	protected Vehicle vehicle;

	public VehicleWrapper( Vehicle v )
	{
		vehicle = v;
		this.ticksRemaining = 10;

		World.getInstance().registerSteppable( this );
	}

	/**
	 * Csökkenti a jármű sebessége alapján a ticksRemaining attribútumot.
	 */
	private void decreaseTicks()
	{
		if ( vehicle != null ) ticksRemaining -= vehicle.getSpeed();
	}

	/**
	 * A RoadSegment ennek hatására indítja el az ütközés folyamatát.
	 */
	public Vehicle getVehicle()
	{
		return this.vehicle;
	}

	/**
	 * A jármű megsemmisítésére szolgáló metódus. Meghívja a <i>currentRS
	 * </i><b>leave</b>() metódusát és null-ra állítja a vehicle referenciát.
	 */
	public void kill()
	{
		currentRS.leave();
		this.vehicle = null;
		World.getInstance().unregisterSteppable( this );
	}

	/**
	 * Jármű átmozgatása a cél útelemre.
	 */
	public void moveVehicle()
	{
		this.currentRS.leave();
		destinationRSW.getRS().enter( this );

		this.currentRS = destinationRSW.getRS();
		this.ticksRemaining = 10;

		destinationRSW = null;
	}

	/**
	 * Órajel fogadására szolgáló metódus.
	 */
	public void step()
	{
		// Lehet, hogy a jármű már halott mikor ideér az órajel.
		if ( vehicle == null ) return;

		// Ha nincs érvényes irány kiválasztva, próbálunk választani
		if ( destinationRSW == null )
		{
			List<Float> angles = this.currentRS.getAngles();
			this.chosenAngle = vehicle.chooseAngle( angles );
			destinationRSW = currentRS.getRSWFromAngle( this.chosenAngle );

			// Ha még mindig nincs érvényes irány kiválasztva, állítsuk le a
			// kocsit és TÉRJÜNK VISSZA
			if ( destinationRSW == null )
			{
				vehicle.setSpeed( 0 );
				return;
			}
		}

		// Van már célirányunk, alkalmazzuk az irányba eső összes szabályt a
		// kocsira
		for ( Rule rule : destinationRSW.getRules() )
		{
			this.vehicle.resetWeight();
			rule.accept( this.vehicle );
		}

		// Csökkentjük a hátralevő óraütések számát
		this.decreaseTicks();
		// Ha elfogyott, akkor tegyük át a céljára
		if ( this.ticksRemaining <= 0 )
		{
			// Betartjuk az elsőbbségi szabályokat (súlyok alapján), ha nem
			// mehet tovább, megállunk
			float entryWeight = destinationRSW.getEntryWeight();

			if ( vehicle.strategy.decideStop( entryWeight, vehicle.getWeight() ) )
			{
				vehicle.applyBrake();
			}
			// Egyébként pedig a jármű saját sebességére/a megengedett maximális
			// sebességre kapcsolunk
			else
			{
				vehicle.releaseBrake();
				this.moveVehicle();
			}
		}
	}

	/**
	 * Visszaadja a célbavett útelem-csomagolóját.
	 * 
	 * @return A cél útelem-csomagoló.
	 */
	public RoadSegmentWrapper getDestinationRSW()
	{
		return destinationRSW;
	}
}
